package org.webby.security;

import org.webby.CookieUtil;
import org.webby.StringUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletRequest;
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.io.UnsupportedEncodingException;

public class WebAuthService {
  public static final String CTX_ATTR_NAME = "webAuthService";

  private static final int DEFAULT_MAX_AGE = 60 * 60 * 24 * 30;
  private static final String REQ_ATTR_NAME = "authTicket";
  private static final String COOKIE_NAME = "auth";

  private final SealedValueService sealedValueService;

  public WebAuthService(SealedValueService sealedValueService) {
    this.sealedValueService = sealedValueService;
  }

  public String getRequestAttributeName() {
    return REQ_ATTR_NAME;
  }

  public String getCookieName() {
    return COOKIE_NAME;
  }

  public static String getAuthenticatedId(ServletRequest request) {
    return (String) request.getAttribute(REQ_ATTR_NAME);
  }

  public AuthTicket authenticate(HttpServletRequest request, HttpServletResponse response) {
    AuthTicket rv = null;

    Cookie cookie = CookieUtil.getCookie(request, COOKIE_NAME);
    if (cookie != null) {
      boolean clearCookie = true;
      try {
        String cookieValue = URLDecoder.decode(cookie.getValue(), "UTF-8");
        try {
          SealedValue sealedValue = SealedValue.parseBase64String(cookieValue);
          if (sealedValueService.verify(sealedValue)) {
            AuthTicket ticket = AuthTicket.parse(StringUtil.bytesToString(sealedValue.getValue()));
            if (!ticket.isExpired()) {
              rv = ticket;
              clearCookie = false;
            }
          } else {
            System.out.println("could not verify value: " + StringUtil.bytesToString(sealedValue.getValue())); // TODO: log
          }
        } catch (ParseException e) {
          System.out.println(e); // TODO: log
        }
      } catch (UnsupportedEncodingException e) {
        throw new RuntimeException("could not url decode auth cookie", e);
      }

      if (clearCookie) {
        clearAuthCookie(request, response);
      }
    }

    return rv;
  }

  public void setAuthCookie(AuthTicket authTicket, HttpServletResponse response) {
    String authTicketStr = authTicket.toString();
    SealedValue sv = sealedValueService.seal(StringUtil.stringToBytes(authTicketStr));
    try {
      String cookieValue = URLEncoder.encode(sv.toBase64String(), "UTF-8");
      Cookie cookie = new Cookie(COOKIE_NAME, cookieValue);
      cookie.setPath("/");
      cookie.setMaxAge(DEFAULT_MAX_AGE);
      response.addCookie(cookie);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("cannot url encode auth cookie", e);
    }
  }

  public void clearAuthCookie(HttpServletRequest request, HttpServletResponse response) {
    CookieUtil.clearCookie(request, response, COOKIE_NAME);
  }
}